home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DJGPP
/
DJSRC111.ZIP
/
go32
/
grprot.asm
< prev
next >
Wrap
Assembly Source File
|
1993-08-13
|
14KB
|
402 lines
;;
;; This is file GRPROT.ASM
;;
;; Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
;; Copyright (C) 1993 Csaba Biegl, csaba@vuse.vanderbilt.edu
;; Copyright (C) 1993 Grzegorz Mazur, gbm@ii.pw.edu.pl
;;
;; This file is distributed under the terms listed in the document
;; "copying.dj", available from DJ Delorie at the address above.
;; A copy of "copying.dj" should accompany this file; if not, a copy
;; should be available from where this file was obtained. This file
;; may not be distributed without a verbatim copy of "copying.dj".
;;
;; This file is distributed WITHOUT ANY WARRANTY; without even the implied
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
;;
; History:270,22
title grprot
.386p
include segdefs.inc
include tss.inc
include gdt.inc
include idt.inc
;------------------------------------------------------------------------
;
; Memory Map (relative to 0xe0000000) :
; 00000000 - 000fffff == read/write area
; 00100000 - 001fffff == read only area
; 00200000 - 002fffff == write only area
; 01000000 - 01ffffff == 16MB read/write area
; 02000000 - 02ffffff == 16MB read only area
; 03000000 - 03ffffff == 16MB write only area
;
; If your board can support separate read & write mappings,
; like the TSENG chips, then either one of two cases applies:
; 1. The read and write mappings are the same, and the rw, r,
; and w areas all have one present bank.
; 2. The read and write mappings are different, and only the
; r and w areas have a mapped bank. Accesses to the rw area
; cause a page fault and the board goes back into case #1.
;
; If your board can't support separate read & write mappings,
; always map the rw, r, and w areas to the same page (case #1 above)
;
; It is up to the programmer to ensure that the program doesn't
; read from the write only area, or write to the read only area.
;
; This method is used because you can't use the string move instructions
; across pages. The "movsx" instruction causes *two* memory references,
; potentially to different banks. The first causes one bank to be
; enabled, and the instruction is restarted. The second access causes
; the second bank to be enabled, and the instruction is *RESTARTED*.
; This means it will attempt the *first* access again, causing it to be
; enabled, ad infinitum.
;
; Thus, bcopy() and memcpy() shouldn't *ever* access the rw area!
;
;------------------------------------------------------------------------
extrn _graphics_pt1_lin:dword ; page table #1
extrn _graphics_pt2_lin:dword ; page table #2
extrn _graphics_pt1_loc:word ; current location of page table #1
extrn _graphics_pt2_loc:word ; current location of page table #2
extrn _graphics_pd_lin:dword ; ptr to graphics section of PD
extrn _graphics_pd_seg_lin:dword ; ptr to graphics section of Pseg Dir
extrn _gr_paging_func:dword ; the paging function
extrn _gr_r_w_page_size:dword ; read or write only page size in 4K units
extrn _gr_sgl_page_size:dword ; R/W page size in 4K units
extrn _gr_r_w_page_shift:byte ; log2 of read or write only page size/4K
extrn _gr_sgl_page_shift:byte ; log2 of R/W page size/4K
extrn _gr_rw_page_offset:byte ; diff between pages in R/W mode (ATI!)
extrn _gr_rw_table_lin:dword ; prepared R/W page table section
extrn _gr_ro_table_lin:dword ; prepared read only page table section
extrn _gr_wo_table_lin:dword ; prepared write only page table section
;;
;; current and previous paging mode codes:
;;
BIGPAGE equ 2
SINGLE equ 4
WRFAULT equ 8
mode_r_w equ 0 ; split 1M pages
mode_r_w_big equ mode_r_w + BIGPAGE ; split 16M pages
mode_sgl equ SINGLE ; single 1M R/W page
mode_sgl_big equ mode_sgl + BIGPAGE ; single 16M R/W page
mode_rr_w equ mode_r_w ; split 1M: read fault
mode_rr_w_big equ mode_r_w_big ; split 16M: read fault
mode_r_ww equ mode_r_w + WRFAULT ; split 1M: write fault (current only)
mode_r_ww_big equ mode_r_w_big + WRFAULT ; split 16M: write fault (current only)
start_data16
cur_p dw 0 ; current mapped r/w or read only page
cur_w dw 0 ; current mapped write only page
mode dw mode_sgl ; current paging mode
VGA_w db 0 ; current VGA write page
VGA_r db 0 ; current VGA read page
end_data16
;------------------------------------------------------------------------
;
; the graphics page fault routine
;
;------------------------------------------------------------------------
start_code16
extrn _page_fault:near
public graphics_fault
graphics_fault:
cli
cld
mov ax,g_core
mov es,ax
mov ebx,cr2
shr ebx,20 ; bx: fault loc/1Meg
mov dx,bx
shr dx,2 ; dx: fault loc/4Meg
and bx,03h ; mask multiple of 1MB bits (0..3)
and dx,0ch ; mask multiple of 16MB bits (0..3)
or bx,dx
; shr ebx,10
; shr bh,2
; shr bx,10
mov bl,cs:mode_table[bx]
mov bp,bx ; bp: new paging mode
lea si,_graphics_pt1_loc ; check page table position in pg dir
cmp bp,mode_r_ww_big
jne check_pgdir
lea si,_graphics_pt2_loc ; here we need the second page table
check_pgdir:
mov ax,[si]
mov ebx,cr2
shr ebx,22
and bx,(03ffffffh SHR 22)
cmp ax,bx ; ax: old, bx: new
je pgdir_done
and eax,0000ffffh
xor edx,edx
mov edi,_graphics_pd_lin
mov ecx,es:[edi+eax*4] ; move page table
mov es:[edi+ebx*4],ecx
mov es:[esi+eax*4],edx ; zero old entry
mov edi,_graphics_pd_seg_lin
mov cl,es:[edi+eax] ; move page table segment
mov es:[edi+ebx],cl
mov es:[edi+eax],dl ; zero old entry
mov [si],bx
pgdir_done:
mov edx,cr2
shr edx,12
and dx,(03ffffffh SHR 12) ; dx: page index where fault occurred
mov bx,dx ; bx: VGA page in 4kByte units
and bx,(00ffffffh SHR 12) ; mask out 16MB region indicators
jmp cs:pginv_table[bp]
pginv_table label word ; dispatch to invalidate old page table(s)
dw offset invalidate_rr_w
dw offset invalidate_rr_w_big
dw offset invalidate_sgl
dw offset invalidate_sgl_big
dw offset invalidate_r_ww
dw offset invalidate_r_ww_big
mode_table label byte ; table of paging modes depending on addr
db mode_sgl
db mode_rr_w
db mode_r_ww
db -1 ; should never need this!!!
db mode_sgl_big
db mode_sgl_big
db mode_sgl_big
db mode_sgl_big
db mode_rr_w_big
db mode_rr_w_big
db mode_rr_w_big
db mode_rr_w_big
db mode_r_ww_big
db mode_r_ww_big
db mode_r_ww_big
db mode_r_ww_big
invalidate_rr_w: ; split page: read fault
and bx,(000fffffh SHR 12) ; mask out 1MB region indicator
invalidate_rr_w_big:
mov cl,_gr_r_w_page_shift
shr dx,cl ; truncate page to VGA limits
shl dx,cl
and bx,(00ffffffh SHR 12) ; mask out 16MB region indicator
shr bx,cl ; figure out VGA page
mov VGA_r,bl
mov edi,_graphics_pt1_lin ; edi: zero in this page table
mov ecx,edi ; ecx: copy to this page table
mov esi,_gr_ro_table_lin ; esi: copy from this prepared table
mov ebx,_gr_r_w_page_size ; ebx: copy this many entries
mov ax,cur_p ; ax: zero from this position
mov cur_p,dx ; dx: copy here, also updated mapping index
jmp invalidate_ptable
invalidate_r_ww: ; split page: write fault
and bx,(000fffffh SHR 12) ; mask out 1MB region indicator
invalidate_r_ww_big:
mov cl,_gr_r_w_page_shift
shr dx,cl ; truncate page to VGA limits
shl dx,cl
and bx,(00ffffffh SHR 12) ; mask out 16MB region indicator
shr bx,cl ; figure out VGA page
mov VGA_w,bl
mov ecx,_graphics_pt1_lin ; ecx: copy to this page table
mov esi,_gr_wo_table_lin ; esi: copy from this prepared table
mov ebx,_gr_r_w_page_size ; ebx: copy this many entries
mov ax,cur_w ; ax: zero from this position
mov cur_w,dx ; dx: copy here, also updated mapping index
test bp,BIGPAGE ; is ptable1 correct?
je invalidate_r_ww_dispatch
mov ecx,_graphics_pt2_lin ; ecx: copy to this page table
invalidate_r_ww_dispatch:
mov di,mode
jmp cs:inv_r_ww_oldmd[di] ; figure out how to invalidate based on old mode
inv_r_ww_oldmd label word
dw inv_r_ww_old_r_w
dw inv_r_ww_old_r_w_big
dw inv_r_ww_old_sgl
dw inv_r_ww_old_sgl_big
inv_r_ww_old_r_w:
mov edi,_graphics_pt1_lin ; edi: zero in this page table
jmp invalidate_ptable
inv_r_ww_old_r_w_big:
mov edi,_graphics_pt2_lin ; edi: zero in this page table
jmp invalidate_ptable
inv_r_ww_old_sgl:
inv_r_ww_old_sgl_big:
mov edi,_graphics_pt1_lin ; edi: zero in this page table
mov ax,cur_p ; ax: zero from this position
jmp invalidate_ptable
invalidate_sgl:
invalidate_sgl_big:
test mode,SINGLE
jne invalidate_one_table_only
mov edi,_graphics_pt1_lin
test mode,BIGPAGE
je invalidate_wr_ptable
mov edi,_graphics_pt2_lin
invalidate_wr_ptable:
mov cx,cur_w
and ecx,1023
lea edi,[edi+ecx*4]
mov ecx,_gr_r_w_page_size
xor eax,eax
rep
db 67h
stosd
invalidate_one_table_only:
mov cl,_gr_sgl_page_shift
shr dx,cl ; truncate page to VGA limits
shl dx,cl
shr bx,cl ; figure out VGA pages
mov cl,_gr_rw_page_offset ; ATI style paging hack
shl bl,cl
mov VGA_w,bl
add bl,cl
mov VGA_r,bl
mov edi,_graphics_pt1_lin ; edi: zero in this page table
mov ecx,edi ; ecx: copy to this page table
mov esi,_gr_rw_table_lin ; esi: copy from this prepared table
mov ebx,_gr_sgl_page_size ; ebx: copy this many entries
mov ax,cur_p ; ax: zero from this position
mov cur_p,dx ; dx: copy here, also updated mapping index
invalidate_ptable:
and eax,1023
lea edi,[edi+eax*4] ; edi: zero page table here
and edx,1023
lea edx,[ecx+edx*4] ; edx: copy into page table here
mov ecx,_gr_sgl_page_size ; entries to clear at edi
test bp,SINGLE ; correct?
jne clear_ptable
mov ecx,_gr_r_w_page_size ; now it is!
clear_ptable:
xor eax,eax
rep
db 67h
stosd
mov edi,edx ; copy into page table here
mov ecx,ebx ; this many entries
mov dx,ds
mov ax,g_core
mov ds,ax
rep
db 67h
movsd
mov ds,dx
and bp,(SINGLE + BIGPAGE) ; update mode
mov mode,bp
mov ax,word ptr VGA_w
call dword ptr [_gr_paging_func] ; call paging func
mov eax,cr3
mov cr3,eax
pop eax
iretd ; back to running program
jmp _page_fault
end_code16
;------------------------------------------------------------------------
; Real mode paging assist code.
; The idea is that we have to call the driver's paging function in real
; mode. GRAPHICS.C's 'graphics_assist' function provides this service
; by intercepting the int 0x10, ah=0xff calls. Unfortunately we cannot
; issue this call from the paging task. Instead the paging routine only
; changes the arena task's eip to point to a routine which invokes
; int 10 first thing when the arena task resumes. A temporary buffer
; is used to save the arena task's eax and ebx. The same buffer
; holds the VGA page values. The virtual address of this buffer is passed
; to the arena task in the eax register. This solution was necessary because
; it is not certain what would happen if we got a second page fault here
; (for which there is a slight chance if we try to use the arena's stack).
; For safety the buffer also contains a busy flag which is cleared by
; the arena routine after completion. The arena task's state is not changed
; if this flag is set. The effect of this is that the VGA is not reprogrammed
; but a garbled screen is still much better than a crashed program! Anyway,
; this should not happen unless some smartass tries to do multitasking
; time-sliced graphics (did anyone say that the graphics libs were
; reentrant?)
;------------------------------------------------------------------------
extrn _real_paging_buffer_lin:dword ; linear address the way I see it
extrn _real_paging_buffer_virt:dword ; address the way the arena sees it
extrn _real_paging_func_virt:dword ; arena address of the 'int 0x10' func
extrn _a_tss:tss_s
start_code16
public _real_paging_routine
_real_paging_routine proc far
mov esi,_real_paging_buffer_lin
cmp byte ptr es:[esi],0 ; busy ?
jne paging_busy ; note: this runs with IT-s disabled
mov byte ptr es:[esi],1 ; so we can do this non-atomic stuff
mov ebx,_a_tss.tss_eax
mov es:[esi+4],ebx ; save arena eax
mov ebx,_a_tss.tss_ebx
mov es:[esi+8],ebx ; save arena ebx
mov es:[esi+12],eax ; put VGA page indices in buffer
mov ebx,_a_tss.tss_eip
mov _a_tss.tss_ebx,ebx ; pass arena's old eip in ebx to it
mov ebx,_real_paging_func_virt
mov _a_tss.tss_eip,ebx ; change arena eip
mov ebx,_real_paging_buffer_virt
mov _a_tss.tss_eax,ebx ; pass buffer address in eax
paging_busy:
ret
_real_paging_routine endp
end_code16
;------------------------------------------------------------------------
; The real mode paging hook in the arena task.
;------------------------------------------------------------------------
_TEXT32 segment dword public 'code' use32
assume cs:_TEXT32,ds:nothing,ss:nothing
public _arena_real_paging_func
_arena_real_paging_func:
push ebx ; save return address
pushf ; save flags
mov ebx,[eax+4]
push ebx ; stack old eax
mov ebx,[eax+8]
push ebx ; stack old ebx
mov ebx,[eax+12] ; VGA page indices
push eax
mov ax,0fffdh ; 'graphics_assist' fnc code
int 10h
pop eax
mov byte ptr [eax],0 ; clear busy flag
pop ebx
pop eax
popf
ret
_TEXT32 ends
;------------------------------------------------------------------------
end